/*
==========
Test.h - Declaration of the Test class, the TestResult class, and associated macros
-class Test - Contains a single unit test
-class TestResult - Contains the results of a single Test
License: BSD
==========
*/
#ifndef TEST_H_INCLUDED
#define TEST_H_INCLUDED
#include <string>
#include <vector>

#define USE_AUTO_TEST 1

/*
==========
Macro: BEGIN_TEST
- Use to begin the declaration of a test case
- test_class_name must be unique
- long_name is the string that represents what the test is testing
==========
*/
#define BEGIN_TEST( test_class_name, long_name )				\
	class test_class_name : public Test							\
	{															\
	public:														\
		test_class_name( ) : Test(long_name)					\
		{														\
			;													\
		}														\
		virtual TestResult operator()( Fixture& fixture )		\
		{														

/*
==========
Macro: END_TEST
- Use to end the declaration of a test case
==========
*/
#define END_TEST()												\
		}														\
	}						

/*
==========
Macro: SIMPLE_TEST_ASSERT
- Use to simplify the creation of a test
- condition is an expression that is the result of some test
- failmsg is the message that is passed if condition is not true
- evaluates condition and then returns
==========
*/
#define SIMPLE_TEST_ASSERT( condition, failmsg )				\
	{															\
		TestResult result( GetName() );							\
																\
		if((!condition)) {										\
			result.SetTestMessage( failmsg );					\
			result.SetPassed(false);							\
		} else {												\
			result.SetPassed(true);								\
		}														\
		return result;											\
	}

/*
==========
Macro: BEGIN_CASCADE_TEST_ASSERT
- Use to simplify the creation of a cascade of simple tests
==========
*/
#define BEGIN_CASCADE_TEST_ASSERT()								\
	{															\
		TestResult result( GetName() );							

/*
==========
Macro: CASCADE_TEST_ASSERT
- Use to simplify the creation of a cascade of simple tests
- evaluation falls through until a failure or END_CASCADE_TEST_ASSERT
==========
*/
#define CASCADE_TEST_ASSERT( condition, failmsg )				\
		{														\
			if((!condition)) {									\
				result.SetTestMessage(failmsg);					\
				result.SetPassed(false);						\
				return result;									\
			}													\
		}

/*
==========
Macro: END_CASCADE_TEST_ASSERT
- Use to simplify the creation of a cascade of simple tests
==========
*/
#define END_CASCADE_TEST_ASSERT()								\
		return result;											\
	}

#if USE_AUTO_TEST
/*
==========
Macro: AUTO_TEST_TABLE_BEGIN
- Use to automate the running of unit tests
==========
*/
#define AUTO_TEST_TABLE_BEGIN()									\
static Test *sUnitTestArr [] = {

/*
==========
Macro: AUTO_TEST_TABLE_ENTRY
- Use to automate the running of unit tests
==========
*/
#define AUTO_TEST_TABLE_ENTRY(test)								\
	test,


/*
==========
Macro: AUTO_TEST_TABLE_END
- Use to automate the running of unit tests
==========
*/
#define AUTO_TEST_TABLE_END()									\
0, };															\
int main ( ) {													\
	Fixture f;													\
	Test **ptr = sUnitTestArr;									\
	while(*ptr!=NULL)											\
		f.AddTest( *(ptr++) );									\
	std::vector<TestResult> results = f.RunAllTests();			\
	bool ret = true;											\
	for(unsigned int ii=0; ii<results.size(); ++ii)	{			\
		printf("%s : %s\n", results[ii].GetTestName().c_str(), results[ii].GetTestMessage().c_str()); \
		ret = ret && results[ii].Passed();						\
	}															\
	return 0;													\
}
#else
#define AUTO_TEST_TABLE_BEGIN()
#define AUTO_TEST_TABLE_ENTRY(test)	
#define AUTO_TEST_TABLE_END()
#endif


class Fixture;

/*
==========
Class: TestResult
- Contains the results of a unit test
==========
*/
class TestResult
{
	bool        m_passed;
	std::string m_test_name;
	std::string m_test_message;

public:
	TestResult ( );
	TestResult ( const std::string& test_name, bool pass = true, const std::string& test_message = "Passed" );
	bool        Passed() const;
	std::string GetTestName( ) const;
	std::string GetTestMessage( ) const;
	
	void SetPassed( bool passed );
	void SetTestName( const std::string& name );
	void SetTestMessage( const std::string& message );
};

/*
==========
Class: Test
- Abstract base class representing a unit test
==========
*/
class Test
{
	std::string  m_name;

public:
	Test( const std::string& name );
	virtual ~Test( ) { ; }
	virtual TestResult operator()( Fixture& fix ) = 0;
	std::string GetName ( ) const;
};

#endif // TEST_H_INCLUDED
